import pygame

from PyPixelCore.Setting import Color_type, show_rect_collision, collision_surface_width, block_surface_width, \
    Block_type, basic_line_interval
from PyPixelCore.block.TextBlock import TextBlock
from queue import Queue

"""
    MultiLineTextBlock --> TextBlock --> Block --> BaseBlock
    多行的文字块
    可直接使用或者继承优化
    功能:
        显示文字
        支持碰撞检测
        支持帧函数与计时器函数
        支持自动检测换行绘制
        支持手动换行控制
        支持手动换行自动换行混合控制
        支持脏精灵优化
        支持行间距
        *** 绘制会额外绘制在屏幕外从而影响效率
"""


class MultiLineTextBlock(TextBlock):
    def __init__(self, text_content="未定义文本", limit_w=0, limit_h=0, point_x=0, point_y=0, layer=0, border_width=1, is_alpha=False):
        self.text_arr = text_content.split('\n')  # 这么写太奇怪了
        self._limit_w = limit_w
        self._limit_h = limit_h
        # self.line_surf_arr = []
        self.line_interval = basic_line_interval
        self.draw_func = base_draw
        super().__init__(text_content, point_x, point_y, border_width, layer, is_alpha)
        self._type = Block_type.multi_line_text_block

    def _reload_image_first(self):
        self.is_dirty = True
        self.reorder_text()
        self.reload_image()

    def update(self):
        self.reload_image()
        # 帧函数的调用
        if self.update_func:
            self.update_func(self)
        # 帧计时器函数的调用
        if self.timer_arr:
            for timer_group in self.timer_arr:
                timer_group[0].next_frame()
                if timer_group[0].is_end:
                    timer_group[1](self)
                    if timer_group[0].type == 0:  # 一次性循环则删除不参与reset
                        self.timer_arr.remove(timer_group)
                    else:
                        timer_group[0].reset()

    def reorder_text(self):  # 重新给多行文本排序 在文字/字体发生改变时进行
        temp_text_array = []
        # 当不存在宽度限制时绘画成TextBlock
        if (not self._limit_w) and self._limit_h > self._font_size:
            surf_size = self.font.size(self._text_content)
            temp_text_array.append(self._text_content)
            if self.is_alpha:
                self.image = pygame.Surface(
                    (surf_size[0] + self.border_width * 2, surf_size[1] + self.border_width * 2), pygame.SRCALPHA)
            else:
                self.image = pygame.Surface(
                    (surf_size[0] + self.border_width * 2, surf_size[1] + self.border_width * 2))
            self.image.fill(self.bk_color)
            return

        # 当位置不足以显示的时候退出
        if self._limit_h < self._font_size and self._limit_w < self._font_size:
            if self._limit_h or self._limit_w:
                if self.is_alpha:
                    self.image = pygame.Surface(
                        (self._limit_w + self.border_width * 2, self._limit_h + self.border_width * 2), pygame.SRCALPHA)
                else:
                    self.image = pygame.Surface(
                        (self._limit_w + self.border_width * 2, self._limit_h + self.border_width * 2))
                self.image.fill(self.bk_color)
            return
        sum_h = 0  # 渲染高度求和
        is_end = False  # 表示后面的内容已经没有必要显示了
        for text in self.text_arr:
            if is_end:
                break
            max_len = len(text) + 1
            original_size = self.font.size(text)
            while self._limit_w and original_size[0] > self._limit_w and not is_end:
                # 从最少适配开始
                start_len = self._limit_w // self._font_size  # 未验证
                # 超出限制,逐渐增大text直到不适配前
                for aim_len in range(start_len, max_len):
                    aim_text = text[:aim_len]
                    aim_size = self.font.size(aim_text)
                    if aim_size[0] > self._limit_w:  # 刚好超出时,回溯一次
                        aim_text = text[:aim_len - 1]
                        temp_text_array.append(aim_text)
                        sum_h += self._font_size + self.line_interval
                        if self.limit_h and sum_h > self.limit_h:
                            is_end = True
                        aim_len -= 1
                        text = text[aim_len:]
                        max_len = len(text) + 1
                        original_size = self.font.size(text)
                        break

            # 对分割后的无法分割的与小于限制宽度的元素的绘制:
            if not is_end:
                # 判断高度是否达标
                temp_text_array.append(text)
                sum_h += self._font_size + self.line_interval
                if self.limit_h and sum_h > self.limit_h:
                    is_end = True
        image_w = self._limit_w + 2 * self.border_width
        image_h = self._limit_h + 2 * self.border_width if self._limit_h else sum_h + 2 * self.border_width
        if self.is_alpha:
            self.image = pygame.Surface((image_w, image_h), pygame.SRCALPHA)
        else:
            self.image = pygame.Surface((image_w, image_h))
        self.image.fill(self.bk_color)
        self.text_arr = temp_text_array
        self.rect.size = self.image.get_size()
        self.reload_image()

    def reload_image(self):
        if not self.is_dirty:
            return
        self.is_dirty = False
        # 绘制文字到主图上
        for line, line_text in enumerate(self.text_arr):
            line_surf = self.font.render(line_text, True, self.font_color, self.bk_color)
            self.image.blit(line_surf, (
                self.border_width, self.border_width + line * (self._font_size + self.line_interval), 0, 0))
            # self.image.blit(line_surf, (self.border_width, self.border_width, self.rect.width, self.rect.height))

        # 绘制方框到主图上
        if self.border_width != 0:
            pygame.draw.rect(self.image, self.border_color, (0, 0, self.rect.width, self.rect.height),
                            width=self.border_width)

    def set_line_interval(self, interval):
        self.is_dirty = True
        self.line_interval = interval
        self.reorder_text()

    def set_text_content(self, text_content):
        self.is_dirty = True
        self._text_content = text_content
        self.text_arr = self._text_content.split('\n')
        self.reorder_text()

    def set_limit_size(self, limit_w=None, limit_h=None):
        self.is_dirty = True
        if limit_w:
            self._limit_w = limit_w
        if limit_h:
            self._limit_h = limit_h
        self.reorder_text()

    @property
    def text_content(self):
        return self._text_content

    @property
    def limit_h(self):
        return self._limit_h

    @property
    def limit_w(self):
        return self._limit_w

    def draw(self, surf):
        base_draw(self, surf)


def base_draw(self: MultiLineTextBlock, surf):
    surf.blit(self.image, self.rect)
    if show_rect_collision:
        # pygame.draw.rect(surf, Color_type.RED, self.rect, width=3)
        pygame.draw.rect(surf, Color_type.BLACK, self.collision_rect, width=collision_surface_width)
        pygame.draw.rect(surf, Color_type.RED, self.rect, width=block_surface_width)

        # pygame.draw.circle(surf, Color_type.RED, self.rect.center, 50, width=2)
        # pygame.draw.line(surf, Color_type.RED, self.rect.bottomleft, self.rect.bottomright, width=4)
        # pygame.draw.polygon(surf, Color_type.RED, [(1, 1), (27, 90), (111, 111)], width=3)
        # pygame.draw.arc(surf, Color_type.RED, self.rect, 0, 5, width=100)
        # pygame.draw.aalines(surf, Color_type.RED, False, [(1, 1), (27, 90), (111, 111)], blend=1)
